import "reflect-metadata";
import interfaces from "./interfaces";
import { METADATA_KEY } from "./constants";
import { join } from 'path';
/** @internal */
import { isJsTsFile, JsTsReg } from './utils';

const recursive = require("recursive-readdir");

class Container {
  instanceMap = new Map()

  bind(id: string, clazz: any, constructorArgs: Array<any>) {
    this.instanceMap.set(id, {
      clazz,
      constructorArgs
    })
  }

  get<T>(id: string): T {
    const target = this.instanceMap.get(id);
    const { clazz, constructorArgs } = target;
    const inst = Reflect.construct(clazz, constructorArgs); // Reflect.construct 类似 new 操作符
    return inst
  }

  public load(register: Function) {
    // 注意，这里只是简化的例子
    register(this.bind.bind(this))
  }
}
const container = new Container()
export default container

export async function binding() {
  // 对目录没有限制，这里只是将常规目录作为示例
  await _loadFile(join(__dirname, './middlewares'));
  await _loadFile(join(__dirname, './controllers'));
  await _loadFile(join(__dirname, './services'));
  container.load(buildProviderModule());
}

export async function _loadFile(path: string) {
  return recursive(path).then((files: Array<any>) => {
    return files
      .filter((file) => isJsTsFile(file))
      .map((file) => file.replace(JsTsReg, ''))
      .forEach((path: string) => {
        require(path);
      });
  }).catch(() => {});
}

function buildProviderModule() {
  return (bind: Function) => {
    let provideMetadata: interfaces.ProvideSyntax[] = Reflect.getMetadata(METADATA_KEY.provide, Reflect) || [];
    provideMetadata.map(metadata => bind(
      metadata.id,
      metadata.clazz,
      metadata.args
    ));
  };
}
